﻿/**
* CRL
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CRL.LambdaQuery
{
    /// <summary>
    /// 返回强类型选择结果查询
    /// </summary>
    /// <typeparam name="TResult"></typeparam>
    public sealed partial class LambdaQueryResultSelect<TResult> : ILambdaQueryResultSelect<TResult>
    {
        Expression resultSelectorBody;
        public Type InnerType
        {
            get
            {
                return BaseQuery.__MainType;
            }
        }
        public string GetQuery(bool appendOrderBy = true)
        {
            return BaseQuery.GetQuery();
        }
        internal LambdaQueryResultSelect(LambdaQueryBase query, Expression _resultSelectorBody)
        {
            resultSelectorBody = _resultSelectorBody;
            BaseQuery = query;

        }
        public LambdaQueryBase BaseQuery { get; set; }
        /// <summary>
        /// 联合查询
        /// 会清除父查询的排序
        /// </summary>
        /// <typeparam name="TResult2"></typeparam>
        /// <param name="resultSelect"></param>
        /// <param name="unionType"></param>
        /// <returns></returns>
        public ILambdaQueryResultSelect<TResult> Union<TResult2>(ILambdaQueryResultSelect<TResult2> resultSelect, UnionType unionType = UnionType.UnionAll)
        {
            BaseQuery.CleanOrder();//清除OrderBy
            BaseQuery.AddUnion(resultSelect.BaseQuery, unionType);
            return this;
        }
        public ILambdaQueryViewJoin<TResult, TResult2> Join<TResult2>(ILambdaQueryResultSelect<TResult2> resultSelect, Expression<Func<TResult, TResult2, bool>> expression, JoinType joinType = JoinType.Inner)
        {
            if (!resultSelect.BaseQuery.__FromDbContext)
            {
                throw new Exception("关联需要由LambdaQuery.CreateQuery创建");
            }

            var typeName = new List<string>();
            foreach (var p in expression.Parameters)
            {
                var prefix = BaseQuery.GetPrefix(p.Type, parameterName: p.Name);
                typeName.Add(prefix);
            }
            var query2 = new LambdaQueryViewJoin<TResult, TResult2>(this, resultSelect);
            var typeQuery = new TypeQuery(typeof(TResult2), typeName[1]);
   
            var baseQuery2 = resultSelect.BaseQuery;
            BaseQuery.QueryParames.AddRange(baseQuery2.QueryParames);

            string innerQuery = baseQuery2.GetQuery();
            typeQuery.InnerQuery = innerQuery;
            BaseQuery.FormatJoinExpression(expression.Parameters, expression.Body, out var result);

            var baseQueryString = BaseQuery.GetQuery();
            BaseQuery.__Relations?.Clear();
            swapTake();//清除take以不会重复拼接

            BaseQuery.joinPackage = Tuple.Create(baseQueryString, typeName[0]);
            BaseQuery.AddInnerRelation(typeQuery, joinType, result);
            BaseQuery.__FromDbContext = true;
            return query2;
        }

        public ILambdaQueryViewJoin<TResult, T2> Join<T2>(Expression<Func<TResult, T2, bool>> expression, JoinType joinType = JoinType.Inner)
        {
            var typeName = new List<string>();
            foreach (var p in expression.Parameters)
            {
                var prefix = BaseQuery.GetPrefix(p.Type, parameterName: p.Name);
                typeName.Add(prefix);
            }
            var query2 = new LambdaQueryViewJoin<TResult, T2>(this, null);
            var typeQuery = new TypeQuery(typeof(T2), typeName[1]);
            typeQuery.TypeQueryEnum = TypeQueryEnum.表;
            //string innerQuery = TypeCache.GetTableName(typeof(T2),BaseQuery.__DbContext);
            //innerQuery = BaseQuery.__DBAdapter.KeyWordFormat(innerQuery);
            //typeQuery.InnerQuery = innerQuery;
            BaseQuery.FormatJoinExpression(expression.Parameters, expression.Body, out var result);
            var baseQueryString = BaseQuery.GetQuery();
            BaseQuery.__Relations?.Clear();
            swapTake();//清除take以不会重复拼接

            BaseQuery.joinPackage = Tuple.Create(baseQueryString, typeName[0]);
            BaseQuery.AddInnerRelation(typeQuery, joinType, result);
            BaseQuery.__FromDbContext = true;
            return query2;
        }
        int oldTake = -1;
        void swapTake()
        {
            if (oldTake > -1)
            {
                BaseQuery.TakeNum = oldTake;
                oldTake = -1;
            }
            else
            {
                oldTake = BaseQuery.TakeNum;
                BaseQuery.TakeNum = 0;
            }
        }

        //string __QueryOrderBy = "";
        /// <summary>
        /// 设置排序
        /// </summary>
        /// <typeparam name="TResult2"></typeparam>
        /// <param name="expression"></param>
        /// <param name="desc"></param>
        /// <returns></returns>
        public ILambdaQueryResultSelect<TResult> OrderBy<TResult2>(Expression<Func<TResult, TResult2>> expression, bool desc = true)
        {
            if (BaseQuery.__Unions != null)
            {
                throw new Exception("union查询不应排序");
            }
            var parameters = expression.Parameters.Select(b => b.Type).ToArray();
            var fields = BaseQuery.GetSelectField(false, expression.Body, false, parameters).mapping;

            //匿名对象列,提取原对象前辍
            var selectFileds = BaseQuery._CurrentSelectFieldCache;
            var orderField = fields.First();
            var selectField = selectFileds.mapping.Find(b => b.ResultName == orderField.ResultName);
            if (selectField != null && !orderField.QueryField.Contains("."))
            {
                //排序字段与查询字段前辍一样
                var index = selectField.QueryField.IndexOf(".");
                orderField.QueryField = selectField.QueryField.Substring(0, index + 1) + orderField.QueryField;
            }
            BaseQuery.SetOrder(orderField, desc);
            return this;
        }
        /// <summary>
        /// 返回自定义类型
        /// </summary>
        /// <typeparam name="TResult2"></typeparam>
        /// <returns></returns>
        public List<TResult2> ToList<TResult2>()
        {
            var db = DBExtendFactory.CreateDBExtend(BaseQuery.__DbContext);
            return db.QueryResult<TResult2>(BaseQuery);
        }
        /// <summary>
        /// 返回筛选类型
        /// </summary>
        /// <returns></returns>
        public List<TResult> ToList()
        {
            if (resultSelectorBody is MemberInitExpression)
            {
                var memberInitExp = (resultSelectorBody as MemberInitExpression);
                resultSelectorBody = memberInitExp.NewExpression;
            }
            var db = DBExtendFactory.CreateDBExtend(BaseQuery.__DbContext);

            if (resultSelectorBody is NewExpression)
            {
                var newExpression = resultSelectorBody as NewExpression;
                var list = db.QueryResult<TResult>(BaseQuery, newExpression);
                ObjectConvert.fillIncudeManyResult(true, BaseQuery.__IncludeTypes, list);
                return list;
            }
            else if (resultSelectorBody is MemberExpression)
            {
                //like Select(b => b.Id)
                var result = db.QueryDynamic(BaseQuery);
                var mExp = resultSelectorBody as MemberExpression;
                var list = new List<TResult>();
                foreach (var item in result)
                {
                    var dic = item as IDictionary<string, object>;
                    var obj = dic[mExp.Member.Name];
                    if (obj is DBNull)
                    {
                        obj = default(TResult);
                    }
                    list.Add((TResult)obj);
                }
                return list;
            }
            else if (resultSelectorBody is ParameterExpression)
            {
                var list = db.QueryResult<TResult>(BaseQuery);
                ObjectConvert.fillIncudeManyResult(true, BaseQuery.__IncludeTypes, list);
                return list;
            }
            else if (resultSelectorBody is MethodCallExpression)
            {
                //like Select(b => b.Id.SUM())
                var result = db.QueryDynamic(BaseQuery);
                var list = new List<TResult>();
                foreach (var item in result)
                {
                    var dic = item as IDictionary<string, object>;
                    var obj = dic.First().Value;
                    if (obj is DBNull)
                    {
                        obj = default(TResult);
                    }
                    else
                    {
                        if (obj.GetType() != typeof(TResult))
                        {
                            obj = Convert.ChangeType(obj, typeof(TResult));
                        }
                    }
                    list.Add((TResult)obj);
                }
                return list;
            }

            throw new Exception("ToList不支持此表达式 " + resultSelectorBody);
        }

        public TResult ToSingle()
        {
            BaseQuery.TakeNum = 1;
            if (BaseQuery.__FromSubQuery)
            {
                return default(TResult);
            }
            return ToList().FirstOrDefault();
        }
        /// <summary>
        /// 返回动态类型
        /// </summary>
        /// <returns></returns>
        public List<dynamic> ToDynamic()
        {
            var db = DBExtendFactory.CreateDBExtend(BaseQuery.__DbContext);
            return db.QueryDynamic(BaseQuery);
        }

        //int prefixIndex2 = 0;
        public ILambdaQuery<TResult> AsQuery()
        {
            //prefixIndex2 += 1;
            var name = typeof(TResult).Name;
            var query = LambdaQueryFactory.CreateLambdaQuery<TResult>(BaseQuery.__DbContext);
            //重新排列前辍
            query.__Prefixs.Clear();
            //todo 暂自关联判断
            //query.__MainTypePrefix = typeof(T) == typeof(T2) ? prefix : "";
            BaseQuery.CleanOrder();
            var sql = BaseQuery.GetQuery();
            var prefix = $"tp{BaseQuery.prefixIndex}.";
            var p2 = query.__Prefixs.Find(b => b.typeName == typeof(TResult).FullName);
            if (p2 == null)
            {
                p2 = new LambdaQueryBase.prefixObj { typeName = typeof(TResult).FullName, prefix = prefix };
                query.__Prefixs.Add(p2);
            }
            p2.prefix = prefix;
            query.__PrefixsQuery.Add(name, new Tuple<string, NewExpression>(sql, resultSelectorBody as NewExpression));
            query.WithNoLock(false);
            query.prefixIndex = BaseQuery.prefixIndex;
            query.QueryParames.AddRange(BaseQuery.QueryParames);
            //query.GetPrefix(typeof(TResult));
            query.__FromDbContext = true;
            query.__IsFromResultSelect = true;
            query.__ResultSelectFields = new List<string>();
            foreach (var m in BaseQuery._CurrentSelectFieldCache.mapping)
            {
                query.__ResultSelectFields.Add(m.ResultName);
            }
            //query.fieldRefs = BaseQuery.fieldRefs;
            return query;
        }

        public ICaseExpression<TResult> CreateCase(string func = "")
        {
            return new CaseExpression<TResult>(BaseQuery, func);
        }

        public string PrintQuery()
        {
            return BaseQuery.PrintQuery();
        }
    }

}
